package com.atguigu.Threads.Exer;

/**
 * 线程通信的应用：经典例题：生产者/消费者问题
 * 生产者（Producer)将产品交给店员（Clerk),而消费者(Customer)从店员处取走产品
 * 店员只能存储固定数量的产品，而生产者试图生产更多的产品，店员叫停生产者，如果有空位了可以在生产，而消费者从店员这里取走产品
 * 没有产品了就等待
 * <p>
 * 分析：
 * 1.是否属于线程安全问题，生产者，消费者
 * 2.共享数据：产品，店员
 * 3.解决方案，同步机制
 * 4.线程之间的通信
 *
 * @author xiaoqi
 * @data 2021/04/07 18:31
 */
//店员类
//产品数目，从生产者取产品，消费者消费产品
class Clerk {
    private int NumProducts = 0;


    public synchronized void ProduceProduct(){
        if (this.NumProducts < 20) {
            NumProducts++;
            System.out.println(Thread.currentThread().getName() + "生产的第" + this.NumProducts + "个产品");
            notify();
        } else {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }

    public synchronized void SaleProduct() {
//        if (this.NumProducts > 0) {
//            System.out.println(Thread.currentThread().getName() + "生产的第" + this.NumProducts + "个产品");
//            NumProducts--;
//            notify();
//        } else {
//            try {
//                wait();
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//        }
        if (this.NumProducts > 0) {
            System.out.println(Thread.currentThread().getName() + "消费的第" + this.NumProducts + "个产品");
            this.NumProducts--;
            notify();
        }else {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

//生产者类
class Producer extends Thread {
    //可以联系到的店员
    private Clerk clerk;

    public Producer(Clerk clerk) {
        this.clerk = clerk;
    }

    @Override
    //生产产品到店中
    public void run() {
        while (true) {
                this.clerk.ProduceProduct();
        }
    }
}

//消费者类
class CustomerD extends Thread {
    //可以联系到的店员
    private Clerk clerk;

    public CustomerD(Clerk clerk) {
        this.clerk = clerk;
    }

    @Override
    public void run() {
        while (true) {
            this.clerk.SaleProduct();
        }
    }
}

public class ProductorDemo {
    public static void main(String[] args) {
        //创建店员类
        Clerk clerk = new Clerk();
        //生产者
        Producer p1 = new Producer(clerk);
        p1.setName("生产者1");
        //消费者
        CustomerD c1 = new CustomerD(clerk);
        CustomerD c2 = new CustomerD(clerk);
        c1.setName("消费者1");
        c2.setName("消费者2");

        p1.start();
        c1.start();
        c2.start();

    }
}
